package com.suray.rgv60.core;

import com.alibaba.fastjson.JSONObject;
import com.suray.basic.wcs.utils.LoggerType;
import com.suray.basic.wcs.utils.WcsFuncUtil;
import com.suray.commin.core.utils.StringUtils;
import com.suray.commin.exception.Rgv60CommFailException;
import com.suray.commin.exception.Rgv60TaskException;
import com.suray.rgv.instance.RgvInstance;
import com.suray.rgv.util.ErrorInfo;
import com.suray.rgv.util.RgvLogger;
import com.suray.rgv60.util.Rgv60BasePro;
import com.suray.rgv60.util.Rgv60ErrorUtil;
import com.suray.type.ErrorLevel;
import com.suray.type.Rgv60LoadMapStatus;
import com.suray.type.SeerRobotPositionStatus;
import suray.rgv.communication.SeerCommManage;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;
import java.util.stream.Stream;

/**
 * 两栖车地图管理
 */
public class Rgv60MapManage {
    //小车基本信息
    private Rgv60Info rgv60Info;
    //通讯
    private SeerCommManage seerCommManage;
    //地图发送、更改地图进度
    private Rgv60BasePro mapPro;
    //当前所在层
    private Integer floor;

    public Rgv60MapManage(Rgv60Info rgv60Info, SeerCommManage seerCommManage) {
        this.rgv60Info = rgv60Info;
        this.seerCommManage = seerCommManage;

        this.mapPro = Rgv60BasePro.INVALID;
    }

    /**
     * 发送地图
     */
    public void sendMap() throws IOException {
        for (String mapPath : RgvInstance.rgvMapManage.getMap().values()) {
            sendMap(mapPath);
        }
    }

    /**
     * 发送地图
     */
    public void sendMap(String mapPath) throws IOException {
        StringBuffer map = new StringBuffer();
        Stream<String> lines = Files.lines(Paths.get(mapPath));

        // 随机行顺序进行数据处理
        lines.forEach(ele -> {
            map.append(ele);
        });
        seerCommManage.sendMap(map.toString());
    }

    /**
     * 切换地图至对应的楼层
     * @param layer
     */
    public void changeMap(Integer layer) throws IOException {
        changeMap(findMapNameByLayer(layer));
    }

    /**
     * 根据楼层查找地图名称
     * @param layer
     * @return
     */
    private String findMapNameByLayer(Integer layer) {
        return RgvInstance.rgvMapManage.getMap().get(layer);
    }

    /**
     * 切换地图
     * @param mapName
     */
    public void changeMap(String mapName) throws IOException {
        if (StringUtils.isEmpty(mapName)) {
            rgv60Info.addError(Rgv60ErrorUtil.CHANGE_MAP_FAIL);
            throw new Rgv60TaskException("切换地图，地图名字不能为空");
        }

        if (!rgv60Info.maps.contains(mapName)) {
            //小车里面没有该地图，发送地图给小车
            sendMap(mapName);
        }

        if (rgv60Info.currentMap.equals(mapName)) {
            return;
        }

        seerCommManage.changeRobotMap(mapName);

        int tick = 20;
        while (true) {
            if (tick == 0) {
                throw new Rgv60TaskException("切换地图失败:" + mapName);
            } else {
                tick--;
            }

            if (rgv60Info.isInterrupt()) {
                rgv60Info.addError(Rgv60ErrorUtil.CHANGE_MAP_FAIL);
                throw new Rgv60TaskException(rgv60Info.serialNum + ": 切换地图被中断");
            }

            if (rgv60Info.currentMap.equals(mapName) && rgv60Info.loadMapStatus == Rgv60LoadMapStatus.SUCCESS) {
                analyzeFloor(mapName);
                RgvLogger.info(LoggerType.MAP, null, rgv60Info.serialNum, "切换地图成功：" + mapName,
                        this.getClass());
                break;
            } else if (rgv60Info.loadMapStatus == Rgv60LoadMapStatus.FAILED) {
                RgvLogger.info(LoggerType.ERROR, null, rgv60Info.serialNum, "切换地图失败：" + mapName,
                        this.getClass());
                rgv60Info.addError(Rgv60ErrorUtil.CHANGE_MAP_FAIL);
                throw new Rgv60TaskException("切换地图失败:" + mapName);
            }

            WcsFuncUtil.delay(100);
        }

        confirmRobotPosition();
    }

    public void confirmRobotPosition() throws IOException {
        if (isPositionOk()) {
            return;
        }

        try {
            seerCommManage.confirmRobotPostion(5);
            checkRobotPosition();
        } catch (Rgv60CommFailException e) {
            rgv60Info.addError(new ErrorInfo(e.getCode(), e.getMsg(), ErrorLevel.ERROR_LEVEL_WCS));
            throw new Rgv60TaskException("异常码：" + e.getCode() + ", 故障描述：" + e.getMsg());
        }
    }

    /**
     * 检测小车定位是否正确
     */
    public void checkRobotPosition() {
        int tick = 0;
        while (true) {
            if (tick < 50) {
                tick++;
            } else {
                rgv60Info.addError(Rgv60ErrorUtil.ROBOT_POSITION_ERROR);
                throw new Rgv60TaskException(rgv60Info.serialNum + "手动校准失败:" + rgv60Info.relocStatus);
            }

            if (isPositionOk()) {
                break;
            }

            WcsFuncUtil.delay(100);
        }
    }

    /**
     * 检测位置是否正确
     * @return
     */
    private boolean isPositionOk() {
        return rgv60Info.relocStatus == SeerRobotPositionStatus.SUCCESS
                && StringUtils.isNotEmpty(rgv60Info.currentStation);
    }

    public Integer getCurrentFloor() {
        return floor;
    }

    /**
     * 分析地图
     */
    public void analyzeMap() {
        analyzeFloor(rgv60Info.currentMap);
//        checkIfHasMap();
    }

    /**
     * 如果机器人没有地图，发送地图给机器人
     */
    private void checkIfHasMap() {
        RgvInstance.rgvMapManage.getMap().values().forEach(map -> {
            for (String s : rgv60Info.maps) {
                if (map.contains(s)) {
                    continue;
                }

                try {
                    sendMap(map);
                } catch (IOException e) {
                    RgvLogger.exceptionLog(LoggerType.MAP, null, s + " 地图发送失败", e, this.getClass());
                }
            }
        });
    }

    /**
     * 分析当前层
     */
    private void analyzeFloor(String currentMap) {
        Map<Integer, String> maps = RgvInstance.rgvMapManage.getMap();
        for (Integer floor : maps.keySet()) {
            if (maps.get(floor).equals(currentMap)) {
                this.floor = floor;
                return;
            }
        }

        this.floor = null;
    }

    /**
     * 下载指定地图
     * @param mapName
     * @return
     * @throws IOException
     */
    public String downloadMap(String mapName) throws IOException {
        JSONObject jsonObject = seerCommManage.downloadMap(mapName);
        if(jsonObject.get("err_msg") != null){
            String errMsg = jsonObject.getString("err_msg");
            throw new RuntimeException(errMsg);
        }else {
            return jsonObject.toString();
        }
    }

    /**
     * 删除指定地图
     * @param mapName
     * @throws IOException
     */
    public void deleteMap(String mapName) throws IOException {
        seerCommManage.deleteMap(mapName);
    }
}
